"""动作解析模块：解析LLM输出的动作"""
import json
import re
from typing import List, Tuple, Dict, Any


def is_json(text: str) -> bool:
    """检查文本是否为有效的JSON"""
    try:
        json.loads(text)
        return True
    except (ValueError, TypeError):
        return False


def check_action_structure(action: str) -> bool:
    """
    检查动作格式是否正确
    
    Args:
        action: LLM输出的完整响应
        
    Returns:
        格式是否有效
    """
    # 检查是否包含 <think> 标签
    think_pattern = r"<think>.*?</think>"
    think_match = re.search(think_pattern, action, re.DOTALL)
    if not think_match:
        return False
    
    # 检查是否包含 <action> 标签
    action_pattern = r"<action>.*?</action>"
    action_match = re.search(action_pattern, action, re.DOTALL)
    if not action_match:
        return False
    
    # 检查是否包含 <invoke> 标签
    invoke_pattern = r"<invoke>.*?</invoke>"
    invoke_match = re.search(invoke_pattern, action, re.DOTALL)
    if not invoke_match:
        return False
    
    return True


def meeting_projection(actions: List[str]) -> Tuple[List[Dict], List[Dict], List[bool]]:
    """
    解析会议安排任务的动作
    
    Args:
        actions: LLM输出的动作列表
        
    Returns:
        action_results: 解析后的动作描述列表
        invoke_results: 解析后的工具调用参数列表
        valids: 每个动作是否有效的标志列表
        
    期望格式:
        <think>思考过程...</think>
        <action>动作描述</action>
        <invoke>
        {
            "tool_name": "query_calendar",
            "tool_input": {
                "persons": ["李明", "王芳"],
                "time_range": "next_week"
            }
        }
        </invoke>
        
    或最终答案格式:
        <think>思考过程...</think>
        <answer>
        {
            "tool_name": "select_time",
            "tool_input": {
                "day": "Monday",
                "time_slot": "afternoon"
            }
        }
        </answer>
    """
    action_results = []
    invoke_results = []
    valids = []
    
    for action in actions:
        valid = True
        
        # 检查是否为最终答案格式
        answer_pattern = r"<answer>(.*?)</answer>"
        answer_match = re.search(answer_pattern, action, re.DOTALL)
        
        if answer_match:
            # 最终答案格式
            answer_content = answer_match.group(1).strip()
            
            try:
                if is_json(answer_content):
                    parsed_answer = json.loads(answer_content)
                    action_results.append(parsed_answer)
                    invoke_results.append(parsed_answer)
                else:
                    # 尝试提取JSON
                    json_pattern = r'\{.*?\}'
                    json_match = re.search(json_pattern, answer_content, re.DOTALL)
                    if json_match:
                        parsed_answer = json.loads(json_match.group(0))
                        action_results.append(parsed_answer)
                        invoke_results.append(parsed_answer)
                    else:
                        valid = False
                        action_results.append({})
                        invoke_results.append({})
            except Exception:
                valid = False
                action_results.append({})
                invoke_results.append({})
            
            valids.append(valid)
            continue
        
        # 普通动作格式
        # 提取 <action> 内容
        action_pattern = r"<action>(.*?)</action>"
        action_match = re.search(action_pattern, action, re.DOTALL)
        
        # 提取 <invoke> 内容
        invoke_pattern = r"<invoke>(.*?)</invoke>"
        invoke_match = re.search(invoke_pattern, action, re.DOTALL)
        
        if not action_match or not invoke_match:
            valid = False
            action_results.append({})
            invoke_results.append({})
            valids.append(valid)
            continue
        
        action_content = action_match.group(1).strip()
        invoke_content = invoke_match.group(1).strip()
        
        # 解析invoke的JSON
        try:
            if is_json(invoke_content):
                invoke_data = json.loads(invoke_content)
            else:
                # 尝试清理并解析
                invoke_content = invoke_content.strip()
                # 移除可能的markdown代码块标记
                invoke_content = re.sub(r'```json\s*', '', invoke_content)
                invoke_content = re.sub(r'```\s*', '', invoke_content)
                invoke_data = json.loads(invoke_content)
            
            # 验证必要字段
            if 'tool_name' not in invoke_data:
                valid = False
                action_results.append({'description': action_content})
                invoke_results.append({})
            else:
                action_results.append({'description': action_content})
                invoke_results.append(invoke_data)
        
        except (json.JSONDecodeError, Exception) as e:
            valid = False
            action_results.append({'description': action_content, 'error': str(e)})
            invoke_results.append({})
        
        valids.append(valid)
    
    return action_results, invoke_results, valids


def extract_think_content(action: str) -> str:
    """
    提取思考内容
    
    Args:
        action: LLM的完整输出
        
    Returns:
        思考内容文本
    """
    think_pattern = r"<think>(.*?)</think>"
    think_match = re.search(think_pattern, action, re.DOTALL)
    
    if think_match:
        return think_match.group(1).strip()
    return ""


def validate_tool_call(tool_name: str, tool_input: Dict) -> Tuple[bool, str]:
    """
    验证工具调用参数是否合法
    
    Args:
        tool_name: 工具名称
        tool_input: 工具输入参数
        
    Returns:
        (是否有效, 错误信息)
    """
    # 定义每个工具的必需参数
    required_params = {
        'query_calendar': ['persons'],
        'query_history': [],  # meeting_topic可选，默认使用当前会议主题
        'negotiate_time': ['person', 'day', 'time_slot'],
        'select_time': ['day', 'time_slot'],
        'calculate': ['expression']
    }
    
    if tool_name not in required_params:
        return False, f"未知的工具: {tool_name}"
    
    required = required_params[tool_name]
    for param in required:
        if param not in tool_input:
            return False, f"缺少必需参数: {param}"
    
    return True, ""


if __name__ == "__main__":
    # 测试用例
    test_actions = [
        """
<think>
首先需要查询所有参会人员的日历，了解他们的空闲时间。
</think>
<action>
查询李明和王芳的下周日历
</action>
<invoke>
{
    "tool_name": "query_calendar",
    "tool_input": {
        "persons": ["李明", "王芳"],
        "time_range": "next_week"
    }
}
</invoke>
        """,
        """
<think>
根据查询结果，周一下午最合适，决定选择这个时间。
</think>
<answer>
{
    "tool_name": "select_time",
    "tool_input": {
        "day": "Monday",
        "time_slot": "afternoon"
    }
}
</answer>
        """
    ]
    
    actions, invokes, valids = meeting_projection(test_actions)
    
    for i, (action, invoke, valid) in enumerate(zip(actions, invokes, valids)):
        print(f"\n测试 {i+1}:")
        print(f"Valid: {valid}")
        print(f"Action: {action}")
        print(f"Invoke: {invoke}")

